package api

import (
	"io/ioutil"
	"log"
	"net/http"
)

type ResponseValue struct {
	Error  error
	Resp   string
	Status int
}

type CombineAPIs struct {
	requestSize int
	result      []*ResponseValue
	responseIn  chan *ResponseValue
	quit        chan struct{}
}

func CreateCombineAPIs(size int) *CombineAPIs {
	if size <= 1 {
		log.Fatal("size is invalid")
		return nil
	}
	return &CombineAPIs{
		requestSize: size,
		result:      make([]*ResponseValue, 0),
		responseIn:  make(chan *ResponseValue, size),
		quit:        make(chan struct{}, size),
	}
}
func (_this *CombineAPIs) Barrier(urls ...string) {
	if urls == nil {
		log.Fatal("urls is nil")
		return
	}
	if len(urls) == 0 {
		log.Fatal("urls length is invalid")
		return
	}
	go func() {
		for _, url := range urls {
			_this._makeRequest(url)
		}
		close(_this.responseIn)
	}()
}
func (_this *CombineAPIs) _makeRequest(url string) {
	result := &ResponseValue{}
	response, error := _getResponseInstance(url)
	if response != nil {
		result.Status = response.StatusCode
	}
	if error != nil {
		result.Error = error
		return
	}
	body, error := ioutil.ReadAll(response.Body)
	defer response.Body.Close()
	if error != nil {
		result.Error = error
		return
	}
	result.Resp = string(body)
	_this.responseIn <- result
	_this.quit <- struct{}{}

}
func (_this *CombineAPIs) ResponseData(callback func(data []*ResponseValue)) {
	if callback == nil {
		log.Fatal("callback is nil")
		return
	}
	var hasError bool
	for resp := range _this.responseIn {
		if resp.Error != nil {
			hasError = true
		}
		_this.result = append(_this.result, resp)
	}
	if hasError {
		panic("combine request error")
	}
	go _this._quit()
	callback(_this.result)
}
func _getResponseInstance(url string) (*http.Response, error) {
	client := http.Client{}
	response, error := client.Get(url)
	if error != nil {
		return nil, error
	}
	return response, nil
}
func (_this *CombineAPIs) _quit() {
	for i := 0; i < _this.requestSize; i++ {
		<-_this.quit
	}
	close(_this.quit)
}
